#pragma once

#include<iostream>
#include<string>
#include<queue>
#include<vector>
#include<memory>
#include"log.hpp"
#include"Lock.hpp"
#include"cond.hpp"
#include"pthread.hpp"

using namespace LockModule;
using namespace thr;
//智能指针
typedef std::shared_ptr<Thread> thread_t;

//默认创建线程的个数
const static int defaultnum= 5;

//用来测试线程的方法
void test1()
{
    while(true)
    {
        LOG(Logeve::DEBUG) << "我是一个测试方法";
        sleep(1);
    }
}


template<class T>
class ThreadPool
{
private:
    //判断任务队列是不是空
    bool isempty(){  return _taskq.empty();  }

    //让线程执行的方法
    void HandTask(std::string name)
    {
        LOG(Logeve::INFO) << "线程进入HandTask逻辑";
         while(true)//让线程不断的拿任务进行处理
        {
            //1.拿任务
            T t;
            {
                LockGuard lock(_lock);//加锁--有可能拿任务的时候用户也在放，所以加锁
                //
                while(isempty() && _isrunning)
                {
                    _wait_num++;
                    
                    //任务队列是空的，让线程等待
                    _cond.wait(_lock);
                    _wait_num--;
                }
                //任务队列为空 && 线程池退出了
                if(isempty() && !_isrunning)
                {
                    break;
                }

                t = _taskq.front();//拿任务
                _taskq.pop();//就任务移走 
            }
            //2.处理任务
            t(name); //规定，未来所有的任务处理，全部都是必须提供（）方法！
        }
        LOG(Logeve::DEBUG) << "线程:" << name << "退出";
    }
public:
    ThreadPool(int num = defaultnum):_num(num),_wait_num(0),_isrunning(false)
    {
        for(int i=0;i<_num;i++)
        {
            _thread.push_back(std::make_shared<Thread>(std::bind(&ThreadPool::HandTask,this,std::placeholders::_1)));//bind绑定方法,所有线程都会跑去执行方法
            LOG(Logeve::INFO) << "构建线程" << _thread.back()->Name() << "对象成功";
        }
    }
    void Equeue(T&& in)
    {
        LockGuard lock(_lock);//加锁
        if(!_isrunning)return;//保证不在新增任务
        _taskq.push(std::move(in));//将任务放到队列里
        //唤醒线程
        if(_wait_num > 0)
        {
            _cond.notify();
        }
    }
    //启动线程
    void star() 
    {
        if(_isrunning)return;
        
        _isrunning = true;
        for(auto&i:_thread)
        {
            i->stat();
            LOG(Logeve::INFO) << "启动线程" << i->Name() << "启动成功...";
        }
    }
    //等待回收线程
    void wait()
    {
        for(auto&i:_thread)
        {
            i->join();
            LOG(Logeve::INFO) << "回收线程" << i->Name() << ".....回收成功";

        }
    }
    //线程退出
    void stop()
    {
        //3.退出了就不能在入任务
        if(_isrunning)
        {
            _isrunning = false; //不工作
            //1.让线程自己退出(要唤醒) && 2.确保历史的任务被处理完了
            if(_wait_num > 0) _cond.notifyall();//唤醒所有线程把历史人物处理完
        }
    }
    ~ThreadPool()
    {

    }
private:
    //直接放线程对象会拷贝，所以用智能指针
    std::vector<thread_t> _thread;//管理线程
    int _num;
    int _wait_num;//等待线程的个数
    std::queue<T> _taskq;//任务队列

    Mutex _lock;//锁
    cond _cond;//条件变量

    bool _isrunning;//线程是否启动
};